package com.strawcom.charmring.bluetooth;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.annotation.TargetApi;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TextView;

import com.android.volley.Request.Method;
import com.strawcom.charmring.App;
import com.strawcom.charmring.BaseActivity;
import com.strawcom.charmring.C;
import com.strawcom.charmring.R;
import com.strawcom.charmring.bean.http.BaseResponse;
import com.strawcom.charmring.bean.http.BleUpgradeUrlRequest;
import com.strawcom.charmring.bean.http.BleUpgradeUrlResponse;
import com.strawcom.charmring.bluetooth.RingBleService.LocalBinder;
import com.strawcom.charmring.bluetooth.upgrade.UpdateService;
import com.strawcom.charmring.util.BaseUtil;
import com.strawcom.charmring.util.DialogUtil;
import com.strawcom.charmring.util.HttpUtil;
import com.strawcom.charmring.util.LogUtil;
import com.strawcom.charmring.util.PreferenceUtil;
import com.strawcom.charmring.view.Loading1View;
import com.strawcom.charmring.view.ProgressLineView;
import com.strawcom.charmring.view.TitleView;

/**
 * @author WangPeng
 */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class RingBleListActivity extends BaseActivity {

	private final Handler handler = new Handler();

	private TitleView titleView;
	private Loading1View viewLoading1;
	private ListView listView;
	private final List<BluetoothDevice> bleDeviceList = new ArrayList<BluetoothDevice>();
	private RingBleService bleService;

	private View layCover;
	private Button btnResearch;
	private TextView txSearchState;

	private View layDInfo;
	private Button btn2Disconnect;
	private TextView txRefreshList;
	private Button btnUpdateBleNickname;
	private TextView txBleNickname;

	private ProgressLineView viewProgressline;
	private Button btnBleUpdate;
	private TextView txUpdateInfo;

	private boolean isScanningBle = false;

	@Override protected void onCreate(Bundle savedInstanceState) {
		setContentView(R.layout.activity_ring_ble_list);
		super.onCreate(savedInstanceState);

		titleView = (TitleView) findViewById(R.id.view_title);
		titleView.setTitleText(R.string.ring_ble_cover);

		viewLoading1 = (Loading1View) findViewById(R.id.view_loading1);
		viewLoading1.startAmin();

		layCover = findViewById(R.id.lay_cover);
		btnResearch = (Button) findViewById(R.id.btn_research);
		btnResearch.setOnClickListener(new View.OnClickListener() {
			@Override public void onClick(View v) {
				startLeScan();
			}
		});

		txSearchState = (TextView) findViewById(R.id.tx_search_state);

		listView = (ListView) findViewById(R.id.listView);
		listView.setAdapter(adapter);

		txRefreshList = new TextView(this);
		txRefreshList.setText(R.string.refresh_list);
		txRefreshList.setTextColor(0xffffffff);
		LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
		int size = BaseUtil.dip2px(this, 10);
		txRefreshList.setPadding(size, size, size, size);
		txRefreshList.setLayoutParams(lp);
		txRefreshList.setGravity(Gravity.CENTER);
		txRefreshList.setOnClickListener(new OnClickListener() {
			@Override public void onClick(View v) {
				txRefreshList.setVisibility(View.GONE);
				btnResearch.performClick();
			}
		});
		titleView.setRightView(txRefreshList);
		txRefreshList.setVisibility(View.GONE);

		layDInfo = findViewById(R.id.lay_dinfo);
		btn2Disconnect = (Button) findViewById(R.id.btn_2disconnect);
		btn2Disconnect.setOnClickListener(new OnClickListener() {
			@Override public void onClick(View v) {
				bleService.setPositiveDisconnect(true);
				String currAddress = bleService.getCurrAddress();
				bleService.disconnectAndClose(currAddress);

				layDInfo.setVisibility(View.GONE);
				layCover.setVisibility(View.VISIBLE);
				btnResearch.setVisibility(View.VISIBLE);
				txSearchState.setVisibility(View.GONE);
				viewLoading1.setVisibility(View.GONE);
				bleDeviceList.clear();
				adapter.notifyDataSetChanged();
			}
		});

		txBleNickname = (TextView) findViewById(R.id.tx_ble_nickname);
		btnUpdateBleNickname = (Button) findViewById(R.id.btn_update_ble_nickname);
		btnUpdateBleNickname.setOnClickListener(new OnClickListener() {
			@Override public void onClick(View arg0) {
				if (bleService != null) {
					String address = bleService.getCurrAddress();
					showUpdateBleNicknameDialog(address, txBleNickname.getText().toString());
				}
			}
		});

		viewProgressline = (ProgressLineView) findViewById(R.id.view_progressline);
		btnBleUpdate = (Button) findViewById(R.id.btn_ble_update);

		boolean needNewFile = !RingBleController.obtainBleUpdateFile(this).exists();
		btnBleUpdate.setText(needNewFile ? R.string.ring_ble_update_1 : R.string.ring_ble_update_2);
		btnBleUpdate.setOnClickListener(new OnClickListener() {
			@Override public void onClick(View v) {
				doUpgradeBle();
				btnBleUpdate.setVisibility(View.GONE);
			}
		});
		btnBleUpdate.setVisibility(View.GONE);

		txUpdateInfo = (TextView) findViewById(R.id.tx_ble_update_info);

		if (PreferenceUtil.readBoolean(this, C.sp.is_downing_ble_file)) {
			txUpdateInfo.setText(R.string.ring_ble_update_3);
			btnBleUpdate.setVisibility(View.GONE);
		}

		bindBleService();
		registerRingMessageReceiver();
		registerUpgradeBleDeviceReceiver();

	}

	@Override protected void onDestroy() {
		super.onDestroy();
		unbindBleService();
		unregisterRingMessageReceiver();
		unregisterUpgradeBleDeviceReceiver();

		viewLoading1.stopAnim();
	}

	private void bindBleService() {
		Intent intent = new Intent(this, RingBleService.class);
		bindService(intent, conn, BIND_AUTO_CREATE);
	}

	private void unbindBleService() {
		unbindService(conn);
	}

	private final ServiceConnection conn = new ServiceConnection() {
		@Override public void onServiceDisconnected(ComponentName name) {
			LogUtil.e("onServiceDisconnected()");
		}

		@Override public void onServiceConnected(ComponentName name, IBinder service) {
			LogUtil.e("onServiceConnected()");
			bleService = ((LocalBinder) service).getService();

			String currAddress = bleService.getCurrAddress();
			if (TextUtils.isEmpty(currAddress)) {
				startLeScan();
			}
			else {
				if (bleService.isCurrConnectionState()) {
					layCover.setVisibility(View.GONE);
					layDInfo.setVisibility(View.VISIBLE);
					txRefreshList.setVisibility(View.GONE);

					setNicknameForConnectedAddress(currAddress);
				}
				else {
					layDInfo.setVisibility(View.GONE);
					showClick2Search();
				}
			}
		}
	};

	private final BluetoothAdapter.LeScanCallback scanCallback = new BluetoothAdapter.LeScanCallback() {
		@Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
			runOnUiThread(new Runnable() {
				@Override public void run() {
//					if (C.bleRing.equals(device.getName()) && !bleDeviceList.contains(device)) {
						if (!bleDeviceList.contains(device)) {
							bleDeviceList.add(device);
							adapter.notifyDataSetChanged();
						}
//					}
				}
			});
		}
	};

	private void startLeScan() {
		if (isScanningBle) {
			LogUtil.d("startLeScan() is scanning");
			return;
		}
		isScanningBle = true;

		if (bleService == null) {
			LogUtil.e("startLeScan() empty bleService");
			return;
		}

		showSearching();
		bleDeviceList.clear();
		adapter.notifyDataSetChanged();

		bleService.startLeScan(scanCallback);
		handler.removeCallbacks(runStopLeScan);
		handler.postDelayed(runStopLeScan, 5000);
	}

	private Runnable runStopLeScan = new Runnable() {
		@Override public void run() {
			stopLeScan();
		}
	};

	private void stopLeScan() {
		isScanningBle = false;
		if (bleService == null) {
			LogUtil.e("startLeScan() empty bleService");
			return;
		}
		bleService.stopLeScan(scanCallback);

		if (bleDeviceList.size() < 1) {
			showNoneDevice();
		}
		else {
			layDInfo.setVisibility(View.GONE);
			layCover.setVisibility(View.GONE);
			txRefreshList.setVisibility(View.VISIBLE);
		}
	}

	private void showNoneDevice() {
		btnResearch.setVisibility(View.VISIBLE);
		txSearchState.setText(R.string.ring_ble_none_device);
		viewLoading1.setVisibility(View.GONE);
	}

	private void showSearching() {
		layCover.setVisibility(View.VISIBLE);
		btnResearch.setVisibility(View.GONE);
		txSearchState.setVisibility(View.VISIBLE);
		txSearchState.setText(R.string.ring_ble_covering);
		viewLoading1.setVisibility(View.VISIBLE);
	}

	private void showClick2Search() {
		layCover.setVisibility(View.VISIBLE);
		btnResearch.setVisibility(View.VISIBLE);
		txSearchState.setVisibility(View.GONE);
		txSearchState.setText(R.string.ring_ble_covering);
		viewLoading1.setVisibility(View.GONE);
	}

	private final BaseAdapter adapter = new BaseAdapter() {
		@Override public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder viewHolder = null;
			if (convertView != null) {
				viewHolder = (ViewHolder) convertView.getTag();
			}
			else {
				convertView = LayoutInflater.from(context).inflate(R.layout.list_content_ring_ble_device, null);
				viewHolder = new ViewHolder();
				viewHolder.txName = (TextView) convertView.findViewById(R.id.tx_name);
				viewHolder.txAddress = (TextView) convertView.findViewById(R.id.tx_address);
				viewHolder.imgLoading = (ImageView) convertView.findViewById(R.id.img_loading);
				convertView.setTag(viewHolder);
			}
			final BluetoothDevice device = bleDeviceList.get(position);

			String lastNick = PreferenceUtil.readString(RingBleListActivity.this, C.sp.ring_ble_address_nick + device.getAddress());
			String lastConnected = PreferenceUtil.readString(RingBleListActivity.this, C.sp.ring_ble_last_address);
			boolean last = device.getAddress().equals(lastConnected);
			if (!TextUtils.isEmpty(lastNick)) {
				viewHolder.txName.setText(lastNick);
			}
			else {
				if (last) {
					String myTmpName = PreferenceUtil.readString(RingBleListActivity.this, C.sp.username);
					if (TextUtils.isEmpty(myTmpName)) {
						myTmpName = PreferenceUtil.readString(RingBleListActivity.this, C.sp.phone);
					}
					viewHolder.txName.setText(myTmpName);
				}
				else {
					viewHolder.txName.setText(device.getName());
				}
			}
			viewHolder.txName.setTextColor(last ? 0xffe03f13 : 0xff333333);
			viewHolder.txName.setTypeface(last ? App.i().tfYouYuan : Typeface.DEFAULT);

			viewHolder.txAddress.setText(device.getAddress());
			viewHolder.imgLoading.setVisibility(View.INVISIBLE);

			final ImageView il = viewHolder.imgLoading;
			convertView.setOnClickListener(new OnClickListener() {
				@Override public void onClick(View v) {
					il.setVisibility(View.VISIBLE);
					bleService.connect(device.getAddress());
				}
			});

			return convertView;
		}

		class ViewHolder {
			TextView txName, txAddress;
			ImageView imgLoading;
		}

		@Override public long getItemId(int position) {
			return position;
		}

		@Override public Object getItem(int position) {
			return bleDeviceList.get(position);
		}

		@Override public int getCount() {
			return bleDeviceList.size();
		}

	};

	private void registerRingMessageReceiver() {
		IntentFilter filter = new IntentFilter();
		filter.addAction(RingBleService.ACTION_GATT_CONNECTED);
		filter.addAction(RingBleService.ACTION_GATT_DISCONNECTED);
		filter.addAction(RingBleService.ACTION_GATT_VERSION_INFO);

		registerReceiver(ringMessageReceiver, filter);
	}

	private void unregisterRingMessageReceiver() {
		unregisterReceiver(ringMessageReceiver);
	}

	private final BroadcastReceiver ringMessageReceiver = new BroadcastReceiver() {
		@Override public void onReceive(Context context, Intent intent) {
			final String action = intent.getAction();
			if (RingBleService.ACTION_GATT_CONNECTED.equals(action)) {
				layDInfo.setVisibility(View.VISIBLE);
				txRefreshList.setVisibility(View.GONE);

				setNicknameForConnectedAddress(bleService.getCurrAddress());

				// 连接蓝牙去读取版本信息
			}
			else if (RingBleService.ACTION_GATT_DISCONNECTED.equals(action)) {
				layDInfo.setVisibility(View.GONE);
				layCover.setVisibility(View.VISIBLE);
				btnResearch.setVisibility(View.VISIBLE);
				txSearchState.setVisibility(View.GONE);
				viewLoading1.setVisibility(View.GONE);
				bleDeviceList.clear();
				adapter.notifyDataSetChanged();
			}
			else if (RingBleService.ACTION_GATT_VERSION_INFO.equals(action)) {
				String ver = intent.getStringExtra(RingBleService.EXTRA_DATA);
				if (!TextUtils.isEmpty(ver)) {
					// requestUpgradeUrl(ver);
				}
			}
		}
	};

	private void requestUpgradeUrl(String bleVersion) {
		BleUpgradeUrlRequest r = new BleUpgradeUrlRequest();
		r.msgid = C.request_msgid_post_firmware_check;
		r.curr_ver = bleVersion;
		HttpUtil.requestJson(Method.POST, r, new HttpUtil.ResponeListener() {
			@Override public void onResponse(final BaseResponse response, final String resultStr) {
				runOnUiThread(new Runnable() {
					public void run() {
						if (0 == response.retcode) {
							// 不需要升级
							txUpdateInfo.setText(R.string.ring_ble_version_1);
						}
						else if (1 == response.retcode) {
							BleUpgradeUrlResponse bur = HttpUtil.gson.fromJson(resultStr, BleUpgradeUrlResponse.class);

							downurl = HttpUtil.url_update + bur.ver_url;
							btnBleUpdate.setVisibility(View.VISIBLE);

							// test
							downUpgradeFile();
						}
					}
				});
			}

			@Override public void onErrorResponse(Exception error) {
			}
		});
	}

	String downurl;

	private void doUpgradeBle() {
		boolean needNewFile = !RingBleController.obtainBleUpdateFile(this).exists();
		if (needNewFile) {
			downUpgradeFile();
			txUpdateInfo.setText(R.string.ring_ble_update_3);
		}
		else {
			upgradeBleDevice();
			txUpdateInfo.setText(R.string.ring_ble_update_4);
			viewProgressline.setVisibility(View.VISIBLE);
		}
	}

	private void downUpgradeFile() {
		if (downurl == null) {
			LogUtil.e("down url null . must request url first!");
			return;
		}
		File upFile = RingBleController.obtainBleUpdateFile(this);
		if (!upFile.exists()) {
			try {
				upFile.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
				return;
			}
		}
		Intent intent = new Intent(this, UpdateService.class);
		intent.putExtra("Key_File_Name", C.app.ble_ring_update);
		intent.putExtra("Key_Down_Url", downurl);
		startService(intent);
	}

	private void upgradeBleDevice() {
		if (bleService != null) {
			bleService.requestDeviceUpgrade(bleService.getCurrAddress(), RingBleController.UPGRADE_1);
		}
	}

	private void registerUpgradeBleDeviceReceiver() {
		IntentFilter filter = new IntentFilter();
		filter.addAction(UpdateService.ACTION_DOWN_OVER);
		registerReceiver(upgradeBleDeviceReceiver, filter);
	}

	private void unregisterUpgradeBleDeviceReceiver() {
		unregisterReceiver(upgradeBleDeviceReceiver);
	}

	private final BroadcastReceiver upgradeBleDeviceReceiver = new BroadcastReceiver() {
		@Override public void onReceive(Context context, Intent intent) {
			final String action = intent.getAction();
			if (UpdateService.ACTION_DOWN_OVER.equals(action)) {
				if (PreferenceUtil.readBoolean(RingBleListActivity.this, C.sp.is_downing_ble_file)) {
					int result = intent.getIntExtra(UpdateService.EXTRA_DATA, UpdateService.DOWN_ERROR);
					if (UpdateService.DOWN_ERROR == result) {
						txUpdateInfo.setText(R.string.ring_ble_update_5);
					}
					else if (UpdateService.DOWN_OK == result) {
						txUpdateInfo.setText(R.string.ring_ble_update_6);
					}
					btnBleUpdate.setVisibility(View.VISIBLE);
				}
			}
		}
	};

	private void setNicknameForConnectedAddress(String currAddress) {
		String lastNick = PreferenceUtil.readString(RingBleListActivity.this, C.sp.ring_ble_address_nick + currAddress);
		if (!TextUtils.isEmpty(lastNick)) {
			txBleNickname.setText(lastNick);
		}
		else {
			String myTmpName = PreferenceUtil.readString(RingBleListActivity.this, C.sp.username);
			if (TextUtils.isEmpty(myTmpName)) {
				myTmpName = PreferenceUtil.readString(RingBleListActivity.this, C.sp.phone);
			}
			txBleNickname.setText(myTmpName);
		}
	}

	private Dialog dlgShowUpdateBleNickname;

	private void showUpdateBleNicknameDialog(final String address, String lastNickname) {
		if (dlgShowUpdateBleNickname == null || !dlgShowUpdateBleNickname.isShowing()) {
			final EditText content = new EditText(RingBleListActivity.this);
			content.setHint(lastNickname);
			dlgShowUpdateBleNickname = DialogUtil.init(this).create(content, true, true).setConfirmListener(new OnClickListener() {
				@Override public void onClick(View view) {
					String nickResult = content.getText().toString();
					if (TextUtils.isEmpty(nickResult)) {
						showToast(R.string.none_nick_name_1);
						return;
					}
					PreferenceUtil.write(RingBleListActivity.this, C.sp.ring_ble_address_nick + address, nickResult);
					txBleNickname.setText(nickResult);
					dlgShowUpdateBleNickname.dismiss();
				}
			}).show();
		}
	}

}
